home *** CD-ROM | disk | FTP | other *** search
/ Mac Easy 2010 May / Mac Life Ubuntu.iso / casper / filesystem.squashfs / usr / lib / firefox-3.0.14 / chrome / browser.jar / content / browser / search / search.xml < prev    next >
Encoding:
Extensible Markup Language  |  2008-04-23  |  29.0 KB  |  738 lines

  1. <?xml version="1.0"?>
  2.  
  3. <!DOCTYPE bindings [
  4. <!ENTITY % searchBarDTD SYSTEM "chrome://browser/locale/searchbar.dtd" >
  5. %searchBarDTD;
  6. <!ENTITY % globalDTD SYSTEM "chrome://global/locale/global.dtd">
  7. %globalDTD;
  8. <!ENTITY % browserDTD SYSTEM "chrome://browser/locale/browser.dtd">
  9. %browserDTD;
  10. ]>
  11.  
  12. <bindings id="SearchBindings"
  13.       xmlns="http://www.mozilla.org/xbl"
  14.       xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
  15.       xmlns:xbl="http://www.mozilla.org/xbl">
  16.  
  17.   <binding id="searchbar">
  18.     <resources>
  19.       <stylesheet src="chrome://browser/content/search/searchbarBindings.css"/>
  20.       <stylesheet src="chrome://browser/skin/searchbar.css"/>
  21.     </resources>
  22.     <content>
  23.       <xul:stringbundle src="chrome://browser/locale/search.properties"
  24.                         anonid="searchbar-stringbundle"/>
  25.  
  26.       <xul:textbox class="searchbar-textbox"
  27.                    anonid="searchbar-textbox"
  28.                    type="autocomplete"
  29.                    flex="1"
  30.                    autocompletepopup="PopupAutoComplete"
  31.                    autocompletesearch="search-autocomplete"
  32.                    autocompletesearchparam="searchbar-history"
  33.                    timeout="250"
  34.                    maxrows="10"
  35.                    completeselectedindex="true"
  36.                    showcommentcolumn="true"
  37.                    tabscrolling="true"
  38.                    xbl:inherits="disabled,disableautocomplete,searchengine,src,newlines">
  39.         <xul:button class="searchbar-engine-button"
  40.                     type="menu"
  41.                     anonid="searchbar-engine-button"
  42.                     popup="_child"
  43.                     chromedir="&locale.dir;">
  44.           <xul:image class="searchbar-engine-image" xbl:inherits="src"/>
  45.           <xul:image class="searchbar-dropmarker-image"/>
  46.           <xul:menupopup class="searchbar-popup"
  47.                          anonid="searchbar-popup"
  48.                          position="after_start">
  49.             <xul:menuseparator/>
  50.             <xul:menuitem class="open-engine-manager"
  51.                           anonid="open-engine-manager"
  52.                           label="&cmd_engineManager.label;"
  53.                           tooltiptext=""
  54.                           oncommand="openManager(event);"/>
  55.           </xul:menupopup>
  56.         </xul:button>
  57.         <xul:hbox class="search-go-container" chromedir="&locale.dir;">
  58.           <xul:image class="search-go-button"
  59.                      anonid="search-go-button"
  60.                      chromedir="&locale.dir;"
  61.                      onclick="handleSearchCommand(event);"
  62.                      tooltiptext="&searchEndCap.label;" />
  63.         </xul:hbox>
  64.       </xul:textbox>
  65.     </content>
  66.  
  67.     <implementation implements="nsIObserver">
  68.  
  69.       <constructor><![CDATA[
  70.         if (this.parentNode.parentNode.localName == "toolbarpaletteitem")
  71.           return;
  72.         setTimeout(function (a) { a.init(); }, 0, this);
  73.       ]]></constructor>
  74.  
  75.       <method name="init">
  76.         <body><![CDATA[
  77.           // Make sure we rebuild the popup in onpopupshowing
  78.           this._needToBuildPopup = true;
  79.  
  80.           // Refresh the display (updating icon, etc)
  81.           this.updateDisplay();
  82.  
  83.           var os =
  84.                Components.classes["@mozilla.org/observer-service;1"]
  85.                          .getService(Components.interfaces.nsIObserverService);
  86.           os.addObserver(this, "browser-search-engine-modified", false);
  87.           
  88.           this._addedObserver = true;
  89.         ]]></body>
  90.       </method>
  91.  
  92.       <destructor><![CDATA[
  93.         if (this._addedObserver) {
  94.           var os = Components.classes["@mozilla.org/observer-service;1"]
  95.                              .getService(Components.interfaces.nsIObserverService);
  96.           os.removeObserver(this, "browser-search-engine-modified");
  97.         }
  98.  
  99.         // Make sure to break the cycle from _texbox to us. Otherwise we leak
  100.         // the world. But make sure it's actually pointing to us.
  101.         if (this._textbox.mController.input == this)
  102.           this._textbox.mController.input = null;
  103.       ]]></destructor>
  104.  
  105.       <field name="_stringBundle">document.getAnonymousElementByAttribute(this,
  106.           "anonid", "searchbar-stringbundle");</field>
  107.       <field name="_textbox">document.getAnonymousElementByAttribute(this,
  108.           "anonid", "searchbar-textbox");</field>
  109.       <field name="_popup">document.getAnonymousElementByAttribute(this,
  110.           "anonid", "searchbar-popup");</field>
  111.       <field name="_ss">null</field>
  112.       <field name="_engines">null</field>
  113.  
  114.       <property name="engines" readonly="true">
  115.         <getter><![CDATA[
  116.           if (!this._engines)
  117.             this._engines = this.searchService.getVisibleEngines({ });
  118.           return this._engines;
  119.         ]]></getter>
  120.       </property>
  121.  
  122.       <field name="searchButton">document.getAnonymousElementByAttribute(this,
  123.           "anonid", "searchbar-engine-button");</field>
  124.  
  125.       <property name="currentEngine"
  126.                 onset="this.searchService.currentEngine = val; return val;">
  127.         <getter><![CDATA[
  128.           var currentEngine = this.searchService.currentEngine;
  129.           // Return a dummy engine if there is no currentEngine
  130.           return currentEngine || {name:"", uri:null};
  131.         ]]></getter>
  132.       </property>
  133.  
  134.       <!-- textbox is used by sanitize.js to clear the undo history when
  135.            clearing form information. -->
  136.       <property name="textbox" readonly="true"
  137.                 onget="return this._textbox;"/>
  138.  
  139.       <property name="searchService" readonly="true">
  140.         <getter><![CDATA[
  141.           if (!this._ss) {
  142.             const nsIBSS = Components.interfaces.nsIBrowserSearchService;
  143.             this._ss =
  144.                  Components.classes["@mozilla.org/browser/search-service;1"]
  145.                            .getService(nsIBSS);
  146.           }
  147.           return this._ss;
  148.         ]]></getter>
  149.       </property>
  150.  
  151.       <property name="value" onget="return this._textbox.value;"
  152.                              onset="return this._textbox.value = val;"/>
  153.  
  154.       <method name="focus">
  155.         <body><![CDATA[
  156.           this._textbox.focus();
  157.         ]]></body>
  158.       </method>
  159.  
  160.       <method name="select">
  161.         <body><![CDATA[
  162.           this._textbox.select();
  163.         ]]></body>
  164.       </method>
  165.  
  166.       <method name="observe">
  167.         <parameter name="aEngine"/>
  168.         <parameter name="aTopic"/>
  169.         <parameter name="aVerb"/>
  170.         <body><![CDATA[
  171.           if (aTopic == "browser-search-engine-modified") {
  172.             switch (aVerb) {
  173.             case "engine-removed":
  174.               this.offerNewEngine(aEngine);
  175.               break;
  176.             case "engine-added":
  177.               this.hideNewEngine(aEngine);
  178.               break;
  179.             case "engine-current":
  180.               // The current engine was changed.  Rebuilding the menu appears to
  181.               // confuse its idea of whether it should be open when it's just
  182.               // been clicked, so we force it to close now.
  183.               this._popup.hidePopup();
  184.               break;
  185.             case "engine-changed":
  186.               // An engine was removed (or hidden) or added, or an icon was
  187.               // changed.  Do nothing special.
  188.             }
  189.  
  190.             // Make sure the engine list is refetched next time it's needed
  191.             this._engines = null;
  192.  
  193.             // Rebuild the popup and update the display after any modification.
  194.             this.rebuildPopup();
  195.             this.updateDisplay();
  196.           }
  197.         ]]></body>
  198.       </method>
  199.  
  200.       <!-- There are two seaprate lists of search engines, whose uses intersect
  201.       in this file.  The search service (nsIBrowserSearchService and
  202.       nsSearchService.js) maintains a list of Engine objects which is used to
  203.       populate the searchbox list of available engines and to perform queries.
  204.       That list is accessed here via this.SearchService, and it's that sort of
  205.       Engine that is passed to this binding's observer as aEngine.
  206.  
  207.       In addition, browser.js fills two lists of autodetected search engines
  208.       (browser.engines and browser.hiddenEngines) as properties of
  209.       mCurrentBrowser.  Those lists contain unnamed JS objects of the form
  210.       { uri:, title:, icon: }, and that's what the searchbar uses to determine
  211.       whether to show any "Add <EngineName>" menu items in the drop-down.
  212.  
  213.       The two types of engines are currently related by their identifying
  214.       titles (the Engine object's 'name'), although that may change; see bug
  215.       335102.  -->
  216.  
  217.       <!-- If the engine that was just removed from the searchbox list was
  218.       autodetected on this page, move it to each browser's active list so it
  219.       will be offered to be added again. -->
  220.       <method name="offerNewEngine">
  221.         <parameter name="aEngine"/>
  222.         <body><![CDATA[
  223.           var allbrowsers = getBrowser().mPanelContainer.childNodes;
  224.           for (var tab = 0; tab < allbrowsers.length; tab++) {
  225.             var browser = getBrowser().getBrowserAtIndex(tab);
  226.             if (browser.hiddenEngines) {
  227.               // XXX This will need to be changed when engines are identified by
  228.               // URL rather than title; see bug 335102.
  229.               var removeTitle = aEngine.wrappedJSObject.name;
  230.               for (var i = 0; i < browser.hiddenEngines.length; i++) {
  231.                 if (browser.hiddenEngines[i].title == removeTitle) {
  232.                   if (!browser.engines)
  233.                     browser.engines = [];
  234.                   browser.engines.push(browser.hiddenEngines[i]);
  235.                   browser.hiddenEngines.splice(i, 1);
  236.                   break;
  237.                 }
  238.               }
  239.             }
  240.           }
  241.           BrowserSearch.updateSearchButton();
  242.         ]]></body>
  243.       </method>
  244.  
  245.       <!-- If the engine that was just added to the searchbox list was
  246.       autodetected on this page, move it to each browser's hidden list so it is
  247.       no longer offered to be added. -->
  248.       <method name="hideNewEngine">
  249.         <parameter name="aEngine"/>
  250.         <body><![CDATA[
  251.           var allbrowsers = getBrowser().mPanelContainer.childNodes;
  252.           for (var tab = 0; tab < allbrowsers.length; tab++) {
  253.             var browser = getBrowser().getBrowserAtIndex(tab);
  254.             if (browser.engines) {
  255.               // XXX This will need to be changed when engines are identified by
  256.               // URL rather than title; see bug 335102.
  257.               var removeTitle = aEngine.wrappedJSObject.name;
  258.               for (var i = 0; i < browser.engines.length; i++) {
  259.                 if (browser.engines[i].title == removeTitle) {
  260.                   if (!browser.hiddenEngines)
  261.                     browser.hiddenEngines = [];
  262.                   browser.hiddenEngines.push(browser.engines[i]);
  263.                   browser.engines.splice(i, 1);
  264.                   break;
  265.                 }
  266.               }
  267.             }
  268.           }
  269.           BrowserSearch.updateSearchButton();
  270.         ]]></body>
  271.       </method>
  272.  
  273.       <method name="updateDisplay">
  274.         <body><![CDATA[
  275.           var uri = this.currentEngine.iconURI;
  276.           this.setAttribute("src", uri ? uri.spec : "");
  277.  
  278.           var name = this.currentEngine.name;
  279.           var text = this._stringBundle.getFormattedString("searchtip", [name]);
  280.           this._textbox.emptyText = name;
  281.           this._textbox.label = text;
  282.           this._textbox.tooltipText = text;
  283.         ]]></body>
  284.       </method>
  285.  
  286.       <!-- Rebuilds the dynamic portion of the popup menu (i.e., the menu items
  287.            for new search engines that can be added to the available list).  This
  288.            is called each time the popup is shown.
  289.       -->
  290.       <method name="rebuildPopupDynamic">
  291.         <body><![CDATA[
  292.           // We might not have added the main popup items yet, do that first
  293.           // if needed.
  294.           if (this._needToBuildPopup)
  295.             this.rebuildPopup();
  296.  
  297.           var popup = this._popup;
  298.           // Clear any addengine menuitems, including addengine-item entries and
  299.           // the addengine-separator.  Work backward to avoid invalidating the
  300.           // indexes as items are removed.
  301.           var items = popup.childNodes;
  302.           for (var i = items.length - 1; i >= 0; i--) {
  303.             if (items[i].getAttribute("class").indexOf("addengine") != -1)
  304.               popup.removeChild(items[i]);
  305.           }
  306.  
  307.           var addengines = getBrowser().mCurrentBrowser.engines;
  308.           if (addengines && addengines.length > 0) {
  309.             const kXULNS =
  310.                "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
  311.  
  312.             // Find the (first) separator in the remaining menu, or the first item
  313.             // if no separators are present.
  314.             var insertLocation = popup.firstChild;
  315.             while (insertLocation.nextSibling &&
  316.                    insertLocation.localName != "menuseparator") {
  317.               insertLocation = insertLocation.nextSibling;
  318.             }
  319.             if (insertLocation.localName != "menuseparator")
  320.               insertLocation = popup.firstChild;
  321.  
  322.             var separator = document.createElementNS(kXULNS, "menuseparator");
  323.             separator.setAttribute("class", "addengine-separator");
  324.             popup.insertBefore(separator, insertLocation);
  325.  
  326.             // Insert the "add this engine" items.
  327.             for (var i = 0; i < addengines.length; i++) {
  328.               var menuitem = document.createElement("menuitem");
  329.               var engineInfo = addengines[i];
  330.               var labelStr =
  331.                   this._stringBundle.getFormattedString("cmd_addFoundEngine",
  332.                                                         [engineInfo.title]);
  333.               menuitem = document.createElementNS(kXULNS, "menuitem");
  334.               menuitem.setAttribute("class", "menuitem-iconic addengine-item");
  335.               menuitem.setAttribute("label", labelStr);
  336.               menuitem.setAttribute("tooltiptext", engineInfo.uri);
  337.               menuitem.setAttribute("uri", engineInfo.uri);
  338.               if (engineInfo.icon)
  339.                 menuitem.setAttribute("src", engineInfo.icon);
  340.               menuitem.setAttribute("title", engineInfo.title);
  341.               popup.insertBefore(menuitem, insertLocation);
  342.             }
  343.           }
  344.         ]]></body>
  345.       </method>
  346.  
  347.       <!-- Rebuilds the list of visible search engines in the menu.  Does not remove
  348.            or update any dynamic entries (i.e., "Add this engine" items) nor the
  349.            Manage Engines item.  This is called by the observer when the list of
  350.            visible engines, or the currently selected engine, has changed.
  351.       -->
  352.       <method name="rebuildPopup">
  353.         <body><![CDATA[
  354.           var popup = this._popup;
  355.  
  356.           // Clear the popup, down to the first separator
  357.           while (popup.firstChild && popup.firstChild.localName != "menuseparator")
  358.             popup.removeChild(popup.firstChild);
  359.  
  360.           const kXULNS =
  361.                "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
  362.  
  363.           var engines = this.engines;
  364.           for (var i = engines.length - 1; i >= 0; --i) {
  365.             var menuitem = document.createElementNS(kXULNS, "menuitem");
  366.             var name = engines[i].name;
  367.             menuitem.setAttribute("label", name);
  368.             menuitem.setAttribute("id", name);
  369.             menuitem.setAttribute("class", "menuitem-iconic searchbar-engine-menuitem");
  370.             // Since this menu is rebuilt by the observer method whenever a new
  371.             // engine is selected, the "selected" attribute does not need to be
  372.             // explicitly cleared anywhere.
  373.             if (engines[i] == this.currentEngine)
  374.               menuitem.setAttribute("selected", "true");
  375.             var tooltip = this._stringBundle.getFormattedString("searchtip", [name]);
  376.             menuitem.setAttribute("tooltiptext", tooltip);
  377.             if (engines[i].iconURI)
  378.               menuitem.setAttribute("src", engines[i].iconURI.spec);
  379.             popup.insertBefore(menuitem, popup.firstChild);
  380.             menuitem.engine = engines[i];
  381.           }
  382.  
  383.           this._needToBuildPopup = false;
  384.         ]]></body>
  385.       </method>
  386.  
  387.       <method name="openManager">
  388.         <parameter name="aEvent"/>
  389.         <body><![CDATA[
  390.           var wm =
  391.                 Components.classes["@mozilla.org/appshell/window-mediator;1"]
  392.                           .getService(Components.interfaces.nsIWindowMediator);
  393.  
  394.           var window = wm.getMostRecentWindow("Browser:SearchManager");
  395.           if (window)
  396.             window.focus()
  397.           else {
  398.             setTimeout(function () {
  399.               openDialog("chrome://browser/content/search/engineManager.xul",
  400.                          "_blank", "chrome,dialog,modal,centerscreen");
  401.             }, 0);
  402.           }
  403.         ]]></body>
  404.       </method>
  405.  
  406.       <method name="selectEngine">
  407.         <parameter name="aEvent"/>
  408.         <parameter name="isNextEngine"/>
  409.         <body><![CDATA[
  410.           // Find the new index
  411.           var newIndex = this.engines.indexOf(this.currentEngine);
  412.           newIndex += (isNextEngine) ? 1 : -1;
  413.  
  414.           if (newIndex >= 0 && newIndex < this.engines.length)
  415.             this.currentEngine = this.engines[newIndex];
  416.  
  417.           aEvent.preventDefault();
  418.           aEvent.stopPropagation();
  419.         ]]></body>
  420.       </method>
  421.  
  422.       <method name="handleSearchCommand">
  423.         <parameter name="aEvent"/>
  424.         <body><![CDATA[
  425.           var textBox = this._textbox;
  426.           var textValue = textBox.value;
  427.  
  428.           var where = "current";
  429.           if (aEvent && aEvent.originalTarget.getAttribute("anonid") == "search-go-button") {
  430.             if (aEvent.button == 2)
  431.               return;
  432.             where = whereToOpenLink(aEvent, false, true);
  433.           }
  434.           else {
  435.             var newTabPref = textBox._prefBranch.getBoolPref("browser.search.openintab");
  436.             if ((aEvent && aEvent.altKey) ^ newTabPref)
  437.               where = "tab";
  438.           }
  439.  
  440.           // Save the current value in the form history
  441.           if (textValue) {
  442.             textBox._formHistSvc.addEntry(textBox.getAttribute("autocompletesearchparam"),
  443.                                           textValue);
  444.           }
  445.  
  446.           this.doSearch(textValue, where);
  447.         ]]></body>
  448.       </method>
  449.  
  450.       <method name="doSearch">
  451.         <parameter name="aData"/>
  452.         <parameter name="aWhere"/>
  453.         <body><![CDATA[
  454.           // null parameter below specifies HTML response for search
  455.           var submission = this.currentEngine.getSubmission(aData, null);
  456.           openUILinkIn(submission.uri.spec, aWhere, null, submission.postData);
  457.         ]]></body>
  458.       </method>
  459.  
  460.     </implementation>
  461.  
  462.     <handlers>
  463.       <handler event="command"><![CDATA[
  464.         const target = event.originalTarget;
  465.         if (target.getAttribute("class").indexOf("addengine-item") != -1) {
  466.           var searchService =
  467.             Components.classes["@mozilla.org/browser/search-service;1"]
  468.                       .getService(Components.interfaces.nsIBrowserSearchService);
  469.           // We only detect OpenSearch files
  470.           var type = Components.interfaces.nsISearchEngine.DATA_XML;
  471.           searchService.addEngine(target.getAttribute("uri"), type,
  472.                                   target.getAttribute("src"), false);
  473.         }
  474.         else if (target.engine)
  475.           this.currentEngine = target.engine;
  476.         else
  477.           return;
  478.  
  479.         this.focus();
  480.         this.select();
  481.       ]]></handler>
  482.  
  483.       <handler event="popupshowing" action="this.rebuildPopupDynamic();"/>
  484.  
  485.       <handler event="DOMMouseScroll"
  486.                phase="capturing"
  487.                action="if (event.ctrlKey) this.selectEngine(event, (event.detail > 0));"/>
  488.     </handlers>
  489.   </binding>
  490.  
  491.   <binding id="searchbar-textbox"
  492.       extends="chrome://global/content/bindings/autocomplete.xml#autocomplete">
  493.     <implementation implements="nsIObserver">
  494.       <constructor><![CDATA[
  495.         if (document.getBindingParent(this).parentNode.parentNode.localName ==
  496.             "toolbarpaletteitem")
  497.           return;
  498.         setTimeout(function(a) { a.initialize(); }, 0, this);
  499.       ]]></constructor>
  500.  
  501.       <destructor><![CDATA[
  502.           var ps2 = Components.classes["@mozilla.org/preferences-service;1"]
  503.                               .getService(Components.interfaces.nsIPrefBranch2);
  504.           ps2.removeObserver("browser.search.suggest.enabled", this);
  505.  
  506.         // Because XBL and the customize toolbar code interacts poorly,
  507.         // there may not be anything to remove here
  508.         try {
  509.           this.controllers.removeController(this.searchbarController);
  510.         } catch (ex) { }
  511.       ]]></destructor>
  512.  
  513.       <field name="_stringBundle"/>
  514.       <field name="_formHistSvc"/>
  515.       <field name="_prefBranch"/>
  516.       <field name="_suggestMenuItem"/>
  517.       <field name="_suggestEnabled"/>
  518.  
  519.       <method name="initialize">
  520.         <body><![CDATA[
  521.           const kXULNS =
  522.             "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
  523.           // Initialize fields
  524.           this._stringBundle = document.getBindingParent(this)._stringBundle;
  525.           this._formHistSvc =
  526.                    Components.classes["@mozilla.org/satchel/form-history;1"]
  527.                              .getService(Components.interfaces.nsIFormHistory2);
  528.           this._prefBranch =
  529.                     Components.classes["@mozilla.org/preferences-service;1"]
  530.                               .getService(Components.interfaces.nsIPrefBranch);
  531.           this._suggestEnabled =
  532.               this._prefBranch.getBoolPref("browser.search.suggest.enabled");
  533.  
  534.           if (this._prefBranch.getBoolPref("browser.urlbar.clickSelectsAll"))
  535.             this.setAttribute("clickSelectsAll", true);
  536.  
  537.           // Add items to context menu and attach controller to handle them
  538.           var textBox = document.getAnonymousElementByAttribute(this,
  539.                                                 "anonid", "textbox-input-box");
  540.           var cxmenu = document.getAnonymousElementByAttribute(textBox,
  541.                                             "anonid", "input-box-contextmenu");
  542.  
  543.           var element = document.createElementNS(kXULNS, "menuseparator");
  544.           cxmenu.appendChild(element);
  545.           element = document.createElementNS(kXULNS, "menuitem");
  546.           var label = this._stringBundle.getString("cmd_clearHistory");
  547.           var akey = this._stringBundle.getString("cmd_clearHistory_accesskey");
  548.           element.setAttribute("label", label);
  549.           element.setAttribute("accesskey", akey);
  550.           element.setAttribute("cmd", "cmd_clearhistory");
  551.  
  552.           cxmenu.appendChild(element);
  553.  
  554.           element = document.createElementNS(kXULNS, "menuitem");
  555.           label = this._stringBundle.getString("cmd_showSuggestions");
  556.           akey = this._stringBundle.getString("cmd_showSuggestions_accesskey");
  557.           element.setAttribute("anonid", "toggle-suggest-item");
  558.           element.setAttribute("label", label);
  559.           element.setAttribute("accesskey", akey);
  560.           element.setAttribute("cmd", "cmd_togglesuggest");
  561.           element.setAttribute("type", "checkbox");
  562.           element.setAttribute("checked", this._suggestEnabled);
  563.           element.setAttribute("autocheck", "false");
  564.  
  565.           this._suggestMenuItem = element;
  566.           cxmenu.appendChild(element);
  567.  
  568.           this.controllers.appendController(this.searchbarController);
  569.  
  570.           // Add observer for suggest preference
  571.           var ps2 = Components.classes["@mozilla.org/preferences-service;1"]
  572.                               .getService(Components.interfaces.nsIPrefBranch2);
  573.           ps2.addObserver("browser.search.suggest.enabled", this, false);
  574.         ]]></body>
  575.       </method>
  576.  
  577.       <method name="openPopup">
  578.         <body><![CDATA[
  579.           var popup = this.popup;
  580.           if (!popup.mPopupOpen) {
  581.             // Initially the panel used for the searchbar (PopupAutoComplete
  582.             // in browser.xul) is hidden to avoid impacting startup / new
  583.             // window performance. The base binding's openPopup would normally
  584.             // call the overriden openAutocompletePopup in urlbarBindings.xml's
  585.             // browser-autocomplete-result-popup binding to unhide the popup,
  586.             // but since we're overriding openPopup we need to unhide the panel
  587.             // ourselves.
  588.             popup.hidden = false;
  589.  
  590.             popup.mInput = this;
  591.             popup.view = this.controller.QueryInterface(Components.interfaces.nsITreeView);
  592.             popup.invalidate();
  593.             
  594.             popup.showCommentColumn = this.showCommentColumn;
  595.             popup.showImageColumn = this.showImageColumn;
  596.  
  597.             document.popupNode = null;
  598.  
  599.             var outerRect = this.getBoundingClientRect();
  600.             var innerRect = this.inputField.getBoundingClientRect();
  601.             var width = outerRect.right - innerRect.left;
  602.             popup.setAttribute("width", width > 100 ? width : 100);
  603.  
  604.             // setConsumeRollupEvent() before we call openPopup(), 
  605.             // see bug #404438 for more details
  606.             popup.popupBoxObject.setConsumeRollupEvent(
  607.               this.consumeRollupEvent ? 
  608.                 Ci.nsIPopupBoxObject.ROLLUP_CONSUME : 
  609.                 Ci.nsIPopupBoxObject.ROLLUP_NO_CONSUME);
  610.             popup.openPopup(null, "", innerRect.left, outerRect.bottom, false, false);
  611.           }
  612.         ]]></body>
  613.       </method>
  614.  
  615.       <method name="observe">
  616.         <parameter name="aSubject"/>
  617.         <parameter name="aTopic"/>
  618.         <parameter name="aData"/>
  619.         <body><![CDATA[
  620.           if (aTopic == "nsPref:changed") {
  621.             this._suggestEnabled =
  622.               this._prefBranch.getBoolPref("browser.search.suggest.enabled");
  623.             this._suggestMenuItem.setAttribute("checked", this._suggestEnabled);
  624.           }
  625.         ]]></body>
  626.       </method>
  627.  
  628.       <method name="openSearch">
  629.         <body>
  630.           <![CDATA[
  631.             // Don't open search popup if history popup is open
  632.             if (!this.popupOpen) {
  633.               document.getBindingParent(this).searchButton.open = true;
  634.               return false;
  635.             }
  636.             return true;
  637.           ]]>
  638.         </body>
  639.       </method>
  640.  
  641.       <!-- overload |onTextEntered| in autocomplete.xml -->
  642.       <method name="onTextEntered">
  643.         <parameter name="aEvent"/>
  644.         <body><![CDATA[
  645.           var evt = aEvent || this.mEnterEvent;
  646.           document.getBindingParent(this).handleSearchCommand(evt);
  647.           this.mEnterEvent = null;
  648.         ]]></body>
  649.       </method>
  650.  
  651.       <!-- nsIController -->
  652.       <field name="searchbarController" readonly="true"><![CDATA[({
  653.         _self: this,
  654.         supportsCommand: function(aCommand) {
  655.           return aCommand == "cmd_clearhistory" ||
  656.                  aCommand == "cmd_togglesuggest";
  657.         },
  658.  
  659.         isCommandEnabled: function(aCommand) {
  660.           if (aCommand == "cmd_clearhistory") {
  661.             var param = this._self.getAttribute("autocompletesearchparam");
  662.             return this._self._formHistSvc.nameExists(param);
  663.           }
  664.           return true;
  665.         },
  666.  
  667.         doCommand: function (aCommand) {
  668.           switch (aCommand) {
  669.             case "cmd_clearhistory":
  670.               var param = this._self.getAttribute("autocompletesearchparam");
  671.               this._self._formHistSvc.removeEntriesForName(param);
  672.               this._self.value = "";
  673.               break;
  674.             case "cmd_togglesuggest":
  675.               // The pref observer will update _suggestEnabled and the menu
  676.               // checkmark.
  677.               this._self._prefBranch.setBoolPref("browser.search.suggest.enabled",
  678.                                                  !this._self._suggestEnabled);
  679.               break;
  680.             default:
  681.               // do nothing with unrecognized command
  682.           }
  683.         }
  684.       })]]></field>
  685.  
  686.       <!-- DND Observer -->
  687.       <field name="searchbarDNDObserver" readonly="true"><![CDATA[({
  688.         mOuter: this,
  689.  
  690.         onDrop: function (aEvent, aXferData, aDragSession) {
  691.           var data = transferUtils.retrieveURLFromData(aXferData.data,
  692.                          aXferData.flavour.contentType);
  693.           if (data) {
  694.             this.mOuter.value = data;
  695.             this.mOuter.onTextEntered(aEvent);
  696.           }
  697.         },
  698.  
  699.         getSupportedFlavours: function () {
  700.           var flavourSet = new FlavourSet();
  701.  
  702.           flavourSet.appendFlavour("text/unicode");
  703.           flavourSet.appendFlavour("text/x-moz-url");
  704.           flavourSet.appendFlavour("application/x-moz-file", "nsIFile");
  705.           return flavourSet;
  706.         }
  707.       })]]></field>
  708.     </implementation>
  709.  
  710.     <handlers>
  711.       <handler event="keypress" keycode="VK_UP" modifiers="accel"
  712.                phase="capturing"
  713.                action="document.getBindingParent(this).selectEngine(event, false);"/>
  714.  
  715.       <handler event="keypress" keycode="VK_DOWN" modifiers="accel"
  716.                phase="capturing"
  717.                action="document.getBindingParent(this).selectEngine(event, true);"/>
  718.  
  719.       <handler event="keypress" keycode="VK_DOWN" modifiers="alt"
  720.                phase="capturing"
  721.                action="return this.openSearch();"/>
  722.  
  723.       <handler event="keypress" keycode="VK_UP" modifiers="alt"
  724.                phase="capturing"
  725.                action="return this.openSearch();"/>
  726.  
  727.       <handler event="keypress" keycode="VK_F4"
  728.                phase="capturing"
  729.                action="return this.openSearch();"/>
  730.  
  731.       <handler event="dragdrop" phase="capturing">
  732.         nsDragAndDrop.drop(event, this.searchbarDNDObserver);
  733.       </handler>
  734.  
  735.     </handlers>
  736.   </binding>
  737. </bindings>
  738.